
package com.gcloud.mesh.dcs.service;


import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import javax.annotation.PostConstruct;

import org.jeecg.common.exception.ParamException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.gcloud.framework.db.PageResult;
import com.gcloud.mesh.config.DataSecurityConfig;
import com.gcloud.mesh.dcs.dao.DataBackupDao;
import com.gcloud.mesh.dcs.dao.DataSecurityDao;
import com.gcloud.mesh.dcs.entity.DataSecurityEntity;
import com.gcloud.mesh.dcs.utils.DataSecurityBackupUtil;
import com.gcloud.mesh.header.enums.DataSecurityFrequency;
import com.gcloud.mesh.header.enums.DataSecurityPolicy;
import com.gcloud.mesh.header.exception.BaseException;
import com.gcloud.mesh.header.exception.DataSecurityErrorCode;
import com.gcloud.mesh.header.msg.dcs.DetailDataSecurityMsg;
import com.gcloud.mesh.header.msg.dcs.PageBackupMsg;
import com.gcloud.mesh.header.msg.dcs.SetDataSecurityMsg;
import com.gcloud.mesh.header.vo.dcs.DataBackupVo;
import com.gcloud.mesh.header.vo.dcs.DataSecurityVo;
import com.gcloud.mesh.quartz.DataSecurityBackupJob;
import com.gcloud.mesh.quartz.QuartzManager;
import com.gcloud.mesh.threads.ThreadManager;
import com.gcloud.mesh.utils.FileUtil;
import com.gcloud.mesh.utils.TimestampUtil;

import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class DataSecurityService {
	
	public static final String ID = "security";
	
	@Autowired
	private DataSecurityConfig dataSecurityConfig;

	@Autowired
	private DataSecurityDao dataSecurityDao;
	
	@Autowired
	private DataBackupDao dataBackupDao;
	
	private static final String JOBNAME = "data_security";
	
	private static final String JOBGROUPNAME = "data_security_group";
	
	private static final String TRIGGERNAME = "data_security";
	
	private static final String TRIGGERGROUPNAME = "data_security_group";
	
	private static final String DATE_FORMAT = "yyyy-MM-dd_HH-mm-ss";
	
	@PostConstruct
	public void init() {
		log.info("[DataSecurityService][init] 备份定时任务初始化...");
		DataSecurityEntity data = dataSecurityDao.getById(ID);
    	if(data != null) {
        	if(data.getEnabled() == true) {
        		QuartzManager.getInstance().addJob(JOBNAME, JOBGROUPNAME, TRIGGERNAME, TRIGGERGROUPNAME, DataSecurityBackupJob.class, data.getCron());
				if(!QuartzManager.getInstance().isStarted()) {
					QuartzManager.getInstance().startJobs();
				}
        	}
    	}
	}

    public void enabled() throws Exception {
		
    	DataSecurityEntity data = dataSecurityDao.getById(ID);
    	if(data != null) {
        	if(data.getEnabled() == true) {
        		throw new BaseException(DataSecurityErrorCode.ALREADY_ENABLED_ERROR);
        	}
        	List<String> updates = new ArrayList<String>();
        	data.setEnabled(true);
        	updates.add("enabled");
        	data.setUpdateTime(new Date());
        	updates.add("update_time");
        	
  	
//        	ThreadManager.submit(new Runnable() {
//
//				@Override
//				public void run() {
					// TODO Auto-generated method stub
        			try {
        				//新增定时任务
    					QuartzManager.getInstance().addJob(JOBNAME, JOBGROUPNAME, TRIGGERNAME, TRIGGERGROUPNAME, DataSecurityBackupJob.class, data.getCron());
    					if(!QuartzManager.getInstance().isStarted()) {
    						QuartzManager.getInstance().startJobs();
    					}
        			}catch(Exception e) {
        				log.error("[DataSecurityService][enabled] QuartzManager的addJob方法异常...");
        			}
								
					log.info("[DataSecurityService][enabled] 备份任务【{}】启用...", data.getCron());
		        	if(DataSecurityPolicy.INCREMENT.equals(DataSecurityPolicy.getByName(data.getPolicy()))) {
		        		Date date = new Date();
		        		String baseDir = new File(dataSecurityConfig.getIncrements(), TimestampUtil.dateToStr(date, DATE_FORMAT)).getPath();
		        		boolean enabled = initIncrementBackup(data, baseDir);
		        		if(enabled) {
		        			data.setBaseDir(baseDir);
		                	updates.add("base_dir");
		        			log.info("[DataSecurityService][enabled] 备份任务启用成功 {}", data.getCron());
		        		}else {
		        			log.error("[DataSecurityService][enabled] 备份任务启用失败 {}", data.getCron());
		        		}
		        	}
		        	
//		        	try {
//		        		QuartzManager.getInstance().resumeJob(JOBNAME, JOBGROUPNAME);
//		        		log.info("[DataSecurityService][enabled] QuartzManager的定时任务运行...【{}】", data.getCron());
//		        	} catch(Exception e) {
//		        		log.info("[DataSecurityService][enabled] QuartzManager的resumeJob方法异常...");
//		        	}	
//				}
//
//        	});
        	try {
        		dataSecurityDao.update(data, updates);
        	}catch(Exception e) {
        		log.error("[DataSecurityService][enabled] 数据保存失败{}", e.getMessage());
        	}

    	}
    }
    
    public void disabled() throws Exception {
		
    	DataSecurityEntity data = dataSecurityDao.getById(ID);
    	if(data != null) {
        	if(data.getEnabled() == false) {
        		throw new BaseException(DataSecurityErrorCode.ALREADY_ENABLED_ERROR);
        	}
        	List<String> updates = new ArrayList<String>();
        	data.setEnabled(false);
        	updates.add("enabled");
        	try {
        		dataSecurityDao.update(data, updates);
        	}catch(Exception e) {
        		log.error("[DataSecurityService][enabled] 数据保存失败{}", e.getMessage());
        	}
//        	ThreadManager.submit(new Runnable() {
//
//				@Override
//				public void run() {
					// TODO Auto-generated method stub	
		        	try {
		        		//删除定时器
		        		QuartzManager.getInstance().removeJob(JOBNAME, JOBGROUPNAME, TRIGGERNAME, TRIGGERGROUPNAME);
		        		log.info("[DataSecurityService][disabled] QuartzManager的定时任务删除...【{}】", data.getCron());
		        	} catch(Exception e) {
		        		log.info("[DataSecurityService][disabled] QuartzManager的resumeJob方法异常...");
		        	}	
//				}
//
//        	});
    	}
    }
	
    public void set(SetDataSecurityMsg msg) throws Exception {
    	if(DataSecurityFrequency.getByName(msg.getFrequency()) == null) {
    		throw new ParamException(DataSecurityErrorCode.FREQUENCY_FORMAT_ERROR);
    	};
    	if(DataSecurityPolicy.getByName(msg.getPolicy()) == null) {
    		throw new ParamException(DataSecurityErrorCode.POLICY_FORMAT_ERROR);
    	};
    	DataSecurityEntity data = dataSecurityDao.getById(ID);
    	if(data != null) {
    		List<String> updates = new ArrayList<String>();
    		String cron = data.getCron();
    		boolean updated = false;
    		if(msg.getFrequency() != null && !getFrequencyFromCron(data.getCron()).equals(msg.getFrequency())) {
    			cron = buildCronWithFrequency(cron, msg.getFrequency());
        		updated = true;
        	}
    		if(msg.getTime() != null && !getTimeFromCron(data.getCron()).equals(msg.getTime())) {
        		cron = buildCronWithTime(cron, msg.getTime());
        		updated = true;
        	}
    		if(updated) {
    			updates.add("cron");
        		data.setCron(cron);
    		}
    		if(msg.getPolicy() != null && !msg.getPolicy().equals(data.getPolicy())) {
        		updates.add("policy");
        		data.setPolicy(msg.getPolicy());
        	}
    		if(updates.size() > 0) {
    			updates.add("update_time");
        		data.setUpdateTime(new Date());
    			try {
            		dataSecurityDao.update(data, updates);
            	}catch(Exception e) {
            		log.error("[DataSecurityService][set] 数据更新失败{}", e.getMessage());
            	}
    		}
//            	if(msg.getFrequency() != null && !getFrequencyFromCron(data.getCron()).equals(msg.getFrequency())) {
        	if(msg.getFrequency() != null) {
				String newCron = buildCronWithFrequency(data.getCron(), msg.getFrequency());
				log.info("[DataSecurityService][set] QuartzManager的modifyJobTime【{}】方法修改...", newCron); 		        				
        		if(msg.getEnabled() && data.getEnabled() != msg.getEnabled()) {
        			ThreadManager.submit(new Runnable() {

						@Override
						public void run() {
							// TODO Auto-generated method stub
							try {
								enabled();
							}catch(Exception e) {
								log.info("[DataSecurityService][set] QuartzManager的modifyJobTime【{}】方法异常...", newCron);
							}
						}
        			});
        			
        		}
        		else if(!msg.getEnabled() && data.getEnabled() != msg.getEnabled()) {
        			ThreadManager.submit(new Runnable() {

						@Override
						public void run() {
							// TODO Auto-generated method stub
							try {
								disabled();
							}catch(Exception e) {
								log.info("[DataSecurityService][set] QuartzManager的modifyJobTime【{}】方法异常...", newCron);
							}
						}
        			});
        		}
        		else if(data.getEnabled() == msg.getEnabled() && msg.getPolicy() != null) {
        			if(data.getEnabled()
        					&& DataSecurityPolicy.INCREMENT.getName().equals(msg.getPolicy())) {
        				//仅在策略启动情况下，单独将策略改为increment
        				ThreadManager.submit(new Runnable() {

							@Override
							public void run() {
								// TODO Auto-generated method stub
								try {
									disabled();
			        				enabled();
								}catch(Exception e) {
									log.info("[DataSecurityService][set] QuartzManager的modifyJobTime【{}】方法异常...", newCron);
								}
								
							}	
        				});
        				
        			}else {
        				QuartzManager.getInstance().modifyJobTime(JOBNAME, JOBGROUPNAME, TRIGGERNAME, TRIGGERGROUPNAME, newCron);
        			}
        		}	
        	}
    	}
    }
	
    public DataSecurityVo detail(DetailDataSecurityMsg msg) throws Exception {
    	DataSecurityEntity data = dataSecurityDao.getById(ID);
    	DataSecurityVo vo = new DataSecurityVo();
    	if(data != null) {
    		vo.setEnabled(data.getEnabled());
    		vo.setPolicy(data.getPolicy());
    		vo.setPolicyCnName(DataSecurityPolicy.getByName(data.getPolicy()).getCnName());
    		vo.setFrequency(getFrequencyFromCron(data.getCron()));
    		vo.setFrequencyCnName(DataSecurityFrequency.getByName(getFrequencyFromCron(data.getCron())).getCnName());
    		vo.setTime(getTimeFromCron(data.getCron()));
    	}
		return vo;
    }
    
    public PageResult<DataBackupVo> pageBackup(PageBackupMsg msg) throws Exception {
    	
    	PageResult<DataBackupVo> res = dataBackupDao.page(msg.getName(), msg.getPolicy(), msg.getPageNo(), msg.getPageSize(), DataBackupVo.class); 
    	res.getList().stream()
    		.forEach( s -> s.setPolicyCnName(DataSecurityPolicy.getByName(s.getPolicy()).getCnName()));
    	return res;
    }

    private String getFrequencyFromCron(String cron) {  	
    	List<String> fields = Arrays.asList(cron.split(" "));
    	String onlyDate = String.format("%s %s %s", fields.get(3), fields.get(4), fields.get(5));
    	return DataSecurityFrequency.getByCron(onlyDate).getName();
    }
    
    private String getTimeFromCron(String cron) {
    	List<String> fields = Arrays.asList(cron.split(" "));
    	String onlyTime = String.format("%s:%s:%s", fields.get(2), fields.get(1), fields.get(0));
    	return onlyTime;
    }
    
    private String buildCronWithFrequency(String cron, String frequency) {
    	List<String> fields = Arrays.asList(cron.split(" "));
    	String newCron = String.format("%s %s %s %s", fields.get(0), fields.get(1), fields.get(2), DataSecurityFrequency.getByName(frequency).getCron());
    	return newCron;
    }
    
    private String buildCronWithTime(String cron, String time) {
    	List<String> fields = Arrays.asList(cron.split(" "));
    	List<String> times = Arrays.asList(time.split(":"));
    	String newCron = String.format("%s %s %s %s %s %s", 
    			Integer.valueOf(times.get(2)), Integer.valueOf(times.get(1)), Integer.valueOf(times.get(0)), fields.get(3), fields.get(4), fields.get(5));
    	return newCron;
    }
    
    public String getCron() {
    	DataSecurityEntity data = dataSecurityDao.getById(ID);
    	return data.getCron();
    }
    
    private boolean initIncrementBackup(DataSecurityEntity data, String incrementalDir) {
//    	String format = "yyyy-MM-dd_HH-mm-ss";
//    	String incrementalDir = new File(dataSecurityConfig.getIncrements(), TimestampUtil.dateToStr(date, format)).getPath();   	
    	if(!FileUtil.mkdir(incrementalDir)) {
    		log.error("[DataSecurityService][initIncrementBackup] 增量备份目录异常");
    		return false;
    	};
    	//①第一次全量备份
    	DataSecurityBackupUtil.backupFull(dataSecurityConfig.getEnable(), incrementalDir, dataSecurityConfig.getHost(), dataSecurityConfig.getPort(),
    			dataSecurityConfig.getUser(), dataSecurityConfig.getPassword());
    	//②第一次增量备份
    	String baseDir = DataSecurityBackupUtil.getBaseDir(incrementalDir);
    	DataSecurityBackupUtil.backupIncrement(dataSecurityConfig.getEnable(), incrementalDir, baseDir, dataSecurityConfig.getHost(), dataSecurityConfig.getPort(),
    			dataSecurityConfig.getUser(), dataSecurityConfig.getPassword());
    	return true;
    }
}
